<template>
    <div class="map-container" id="map"></div>
    <div class="map-switch">
        <el-button type="primary" @click="switchView('矢量')">矢量</el-button>
        <el-button type="primary" @click="switchView('深色')">深色</el-button>
        <el-button type="primary" @click="switchView('影像')">影像</el-button>
    </div>
</template>

<script lang="ts" setup>
import { nanoid } from 'nanoid';
import { Feature, ImageTile, Map, MapBrowserEvent, Tile, View } from 'ol';
import { Coordinate } from 'ol/coordinate';
import { getTopLeft, getWidth } from 'ol/extent';
import { LineString, MultiPolygon, Polygon } from 'ol/geom';
import BaseLayer from 'ol/layer/Base';
import TileLayer from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';
import { Projection, fromLonLat, get as getProjection } from 'ol/proj';
import { XYZ } from 'ol/source';
import ImageTileSource from 'ol/source/ImageTile';
import VectorSource from 'ol/source/Vector';
import { Fill, Stroke, Style, Text } from 'ol/style';
import { WMTS } from 'ol/source';
import WMTSTileGrid from 'ol/tilegrid/WMTS';
import { onMounted, ref } from 'vue';
import { buffer, lineString } from '@turf/turf';
import beijing from './beijing.json';
import { FeatureCollection } from 'geojson';

console.log(beijing);

const map = ref();
const layer = ref();
const source = ref();
const projection = getProjection('EPSG:3857') as Projection;
const projectionExtent = projection.getExtent();
const size = getWidth(projectionExtent) / 256;
const resolutions = new Array(19);
const matrixIds = new Array(19);
for (let z = 0; z < 19; ++z) {
    resolutions[z] = size / Math.pow(2, z);
    matrixIds[z] = `EPSG:900913:${z}`;
}

const polygonStyle = new Style({
    fill: new Fill({ color: [0, 128, 255, 0.5] }),
    stroke: new Stroke({ color: [0, 128, 255, 0.8], width: 3 }),
    text: new Text({
        font: '18px 微软雅黑',
        textAlign: 'center',
        offsetY: 25,
        fill: new Fill({ color: '#f56c6c' }),
        stroke: new Stroke({
            color: '#ffffff',
            width: 3
        })
    })
});

function darken(imageTile: Tile, src: string) {
    const img = new Image();
    const canvas = document.createElement('canvas');
    const imgTile = imageTile as ImageTile;
    img.setAttribute('crossOrigin', 'anonymous');
    img.onload = function () {
        const w = img.width;
        const h = img.height;
        canvas.width = w;
        canvas.height = h;
        const context = canvas.getContext('2d');
        if (context) {
            context.clearRect(0, 0, img.width, img.height);
            context.drawImage(img, 0, 0, w, h, 0, 0, w, h);
            const imgInner = imgTile.toDataURL('image/png');
        }
    };
    img.src = src;
}

const layers: BaseLayer[] = [
    new TileLayer({
        visible: true,
        properties: { name: '矢量' },
        source: new ImageTileSource({
            url: `http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7`,
            minZoom: 5,
            maxZoom: 18
        })
    }),
    new TileLayer({
        visible: false,
        properties: { name: '深色' },
        source: new XYZ({
            url: '',
            tileLoadFunction: darken
        })
    }),
    new TileLayer({
        visible: false,
        properties: { name: '影像' },
        source: new WMTS({
            url: '',
            layer: 'XXXX',
            matrixSet: 'EPSG:900913',
            format: 'image/png',
            projection: projection,
            tileGrid: new WMTSTileGrid({
                origin: getTopLeft(projectionExtent),
                resolutions: resolutions,
                matrixIds: matrixIds,
                tileSize: 256
            }),
            version: '1.0.0',
            style: '',
            wrapX: true
        })
    })
];

function switchView(e: string) {
    layers.forEach((item: BaseLayer) => {
        const prop = item.getProperties();
        item.setVisible(prop.name === e);
    });
}

onMounted(() => {
    map.value = new Map({
        target: 'map',
        view: new View({
            center: fromLonLat([116.3909, 39.9175]),
            zoom: 12,
            minZoom: 9,
            maxZoom: 15,
            projection: 'EPSG:3857'
        }),
        layers: layers as BaseLayer[]
    });
    source.value = new VectorSource({ wrapX: true });
    layer.value = new VectorLayer({
        source: source.value,
        style: polygonStyle
    });
    map.value.addLayer(layer.value);
    map.value.getView().setZoom(12);

    addDistrictPolygonFeature(beijing as FeatureCollection);
    addLineStringAndBuffer();

    map.value.on('moveend', (e: MapBrowserEvent) => {
        console.log(e.map.getView().getZoom(), 'zoom');
        if (map.value.getView().getZoom() > 12) {
            layer.value.setVisible(false);
        } else {
            layer.value.setVisible(true);
        }
    });
});

function addDistrictPolygonFeature(featureColl: FeatureCollection) {
    featureColl.features.forEach((item) => {
        const prop = item.properties || {};
        const coordinates = item.geometry.coordinates as Coordinate[][][];

        const arr = coordinates[0][0].map((v: Coordinate) => {
            return fromLonLat(v, 'EPSG:3857');
        });

        const feature = new Feature({
            type: 'MultiPolygon',
            geometry: new MultiPolygon([[arr]])
        });
        feature.setId(nanoid());

        const style = polygonStyle.clone();
        style.getText()?.setText(prop.name);
        feature.setStyle(style);

        source.value.addFeature(feature);
    });
}

function addLineStringAndBuffer() {
    const coordinateArr = [
        [116.35038986206051, 39.90605759303833],
        [116.37768402099609, 39.90566254894742],
        [116.39124526977538, 39.906189273895706],
        [116.41098632812498, 39.90684767438634],
        [116.42901077270507, 39.90711103281092]
    ];
    const coordinates = coordinateArr.map((v: number[]) => {
        return fromLonLat(v, 'EPSG:3857');
    });
    const feature = new Feature({
        type: 'LineString',
        geometry: new LineString(coordinates),
        properties: { name: 'hello' }
    });
    feature.setStyle(
        new Style({
            fill: new Fill({ color: [255, 128, 0, 0.5] }),
            stroke: new Stroke({ color: [208, 12, 12, 1], width: 4 })
        })
    );
    source.value.addFeature(feature);

    const resultBuffer = buffer(lineString(coordinateArr), 2, {
        units: 'kilometers'
    });
    const buffCoordinates =
        resultBuffer?.geometry.coordinates.map((v) => {
            return v.map((vv) => fromLonLat(vv as Coordinate, 'EPSG:3857'));
        }) || [];
    const buffFeature = new Feature({
        type: 'Polygon',
        geometry: new Polygon(buffCoordinates)
    });
    source.value.addFeature(buffFeature);
}
</script>

<style lang="scss" scoped>
.map-container {
    width: 100%;
    height: calc(100vh - 100px);
}
</style>